package org.yu.team2023.flashdays.net;

import lombok.Getter;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.network.PacketDistributor;
import org.yu.team2023.flashdays.FDConfig;
import org.yu.team2023.flashdays.client.render.DamageParticlesManager;

import java.util.Objects;
import java.util.UUID;
import java.util.function.Supplier;

public class DamageParticlePackage extends Vec3 {


    public static final int MAX_AGE = 60;
    public final Component text;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof DamageParticlePackage that)) return false;
        if (!super.equals(o)) return false;
        return Objects.equals(uuid, that.uuid);
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), uuid);
    }

    public final UUID uuid;

    public boolean selfShow = false;
    public double x;
    public double y;
    public double z;
    public float scale = 1;
    public int age = 0;
    @Getter
    public String damageId;

    protected DamageParticlePackage(Component text, UUID uuid, double x, double y, double z, String damageId) {
        super(x, y, z);
        this.text = text;
        this.uuid = uuid;
        this.x = x;
        this.y = y;
        this.z = z;
        this.damageId = damageId;
    }

    public static DamageParticlePackage create(FriendlyByteBuf buf) {
        var res = new DamageParticlePackage(
                buf.readComponent(),
                buf.readUUID(),
                buf.readDouble(),
                buf.readDouble(),
                buf.readDouble(),
                buf.readUtf()
        );
        res.selfShow = buf.readBoolean();
        res.scale = buf.readFloat();
        return res;
    }

    public static DamageParticlePackage formEntity(Entity entity, Component damage, DamageSource damageSource) {
        double d = Mth.lerp(Math.random(), 0d, entity.getBbWidth() / 2d);
        Vec3 pos = entity.position().add(d, entity.getBbHeight(), d);
        return new DamageParticlePackage(damage, entity.getUUID(), pos.x(), pos.y(), pos.z(), damageSource.getMsgId());
    }

    public static DamageParticlePackage formEntity(Entity entity, String text, String id) {
        double d = Mth.lerp(Math.random(), 0d, entity.getBbWidth() / 2d);
        Vec3 pos = entity.position().add(d, entity.getBbHeight(), d);
        return new DamageParticlePackage(Component.literal(text), entity.getUUID(), pos.x(), pos.y(), pos.z(), id);
    }

    public static void sendToClient(ServerPlayer serverPlayer, DamageParticlePackage particlePackage) {
        FlashNet.channel.send(PacketDistributor.PLAYER.with(() -> serverPlayer), particlePackage);
    }

    public DamageParticlePackage shelfShow() {
        this.selfShow = true;
        return this;
    }

    public void toBytes(FriendlyByteBuf buf) {
        buf.writeComponent(text);
        buf.writeUUID(uuid);
        buf.writeDouble(x);
        buf.writeDouble(y);
        buf.writeDouble(z);
        buf.writeUtf(damageId);
        buf.writeBoolean(selfShow);
        buf.writeFloat(scale);
    }

    public void handle(Supplier<NetworkEvent.Context> ctx) {
        ctx.get().enqueueWork(() -> {
            if (ctx.get().getDirection().getReceptionSide() == LogicalSide.CLIENT)
                if (FDConfig.ENABLE_SHOW_DAMAGE_CLIENT.get())
                    DamageParticlesManager.PARTICLES.add(this);
        });
        ctx.get().setPacketHandled(true);
    }


    public void tick() {
        if (age < MAX_AGE)
            age++;
    }

    public void move(double x, double y, double z) {
        this.x += x;
        this.y += y;
        this.z += z;
    }

    public float getScale() {
        if (age <= 20) {
            return Mth.lerp((float) age / 20f, 0, 1) * scale;
        } else return scale;
    }

    public DamageParticlePackage setScale(float scale) {
        this.scale = scale;
        return this;
    }

    public boolean camRemoved() {
        return age >= MAX_AGE;
    }

}
